package org.zoomdev.zoom.web.action.impl;

import org.zoomdev.zoom.common.filter.MethodFilter;
import org.zoomdev.zoom.common.filter.impl.PatternClassAndMethodFilter;
import org.zoomdev.zoom.common.utils.OrderedList;
import org.zoomdev.zoom.web.action.ActionInterceptor;
import org.zoomdev.zoom.web.action.ActionInterceptorFactory;

import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public final class ActionInterceptorFactoryImpl implements ActionInterceptorFactory {
    private static final int MAX = 5;
    private final OrderedList<Object> list = new OrderedList<>();

    public ActionInterceptorFactoryImpl() {

    }

    @Override
    public void add(ActionInterceptor interceptor, String pattern, int order) {
        list.add(new InterceptorInfo(interceptor, new PatternClassAndMethodFilter(pattern)), order);
    }

    @Override
    public <T> void add(State<T> state, T interceptor, String pattern, int order) {
        list.add(new InterceptorInfo<T>(interceptor, new PatternClassAndMethodFilter(pattern)), order);
    }

    @Override
    public void add(ActionInterceptor interceptor, MethodFilter filter, int order) {
        list.add(new InterceptorInfo(interceptor, filter), order);
    }

    @Override
    public <T> void add(State<T> state, T interceptor, MethodFilter filter, int order) {
        list.add(new InterceptorInfo<T>(interceptor, filter), order);
    }


    @Override
    public <T> T[] create(State<T> state, Class<?> controllerClass, Method method) {
        List<T> tmp = new ArrayList<>();
        OrderedList<Object> list = this.list;
        for (int i = 0, c = list.size(); i < c; ++i) {
            InterceptorInfo<T> interceptorInfo = (InterceptorInfo<T>) list.get(i);
            if (state.type().isAssignableFrom(interceptorInfo.interceptor.getClass())) {
                if (interceptorInfo.filter.accept(controllerClass, method)) {
                    tmp.add(interceptorInfo.interceptor);
                }
            }
        }
        if (tmp.size() == 0) {
            return null;
        }
        T[] array = (T[]) Array.newInstance(state.type(), tmp.size());
        return tmp.toArray(array);
    }


    private static final class InterceptorInfo<T> {
        final T interceptor;
        final MethodFilter filter;

        InterceptorInfo(T interceptor, MethodFilter filter) {
            this.interceptor = interceptor;
            this.filter = filter;
        }
    }
}
